全文6985字,阅读需18分钟。
目录
四、Bash 变量
4.1 变量的定义
4.2 变量的分类
4.3 用户自定义变量
4.3.1 变量定义
4.3.2 变量调用
4.3.3 变量查看
4.3.4 变量删除
4.4 环境变量
4.4.1 环境变量设置
4.4.2 环境变量查询
4.4.3 环境变量删除
4.4.4 系统默认环境变量
4.4.5 PATH 变量
4.4.6 PS1 变量
4.4.7 LANG 语系变量
4.5 位置参数变量
4.6 预定义变量
4.7 接收键盘输入
在定义变量时,有一些规则需要遵守:
变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name”则是错误的。
在 Bash 中,变量的默认类型都是字符串型,如果要进行数值运算,则必修指定变量类型为数值型。
变量用等号连接值,等号左右两侧不能有空格。
变量的值如果有空格,需要使用单引号或双引号包括。如:“test="hello world!”
。其中双引号括起来的内容“$”
、“\”
和反引号都拥有特殊含义,而单引号括起来的内容都是普通字符。
在变量的值中,可以使用“\”
转义符。
如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含"$变量名"
或用${变量名}
包含变量名。例如:
[root@localhost ~]# test=123
[root@localhost ~]# test="$test"456
[root@localhost ~]# echo $test
123456
#叠加变量 test,变量值变成了 123456
[root@localhost ~]# test=${test}789
[root@localhost ~]# echo $test
123456789
#再叠加变量 test,变量值编程了 123456789
变量值的叠加可以使用两种格式:“$变量名”
或${变量名}
如果是把命令的结果作为变量值赋予变量,则需要使用反引号或$()包含命令。例如:
[root@localhost ~]# test=$(date)
[root@localhost ~]# echo $test
2021 年 06 月 12 日 星期六 11:27:50 CST
环境变量名建议大写,便于区分。
用户自定义变量:这种变量是最常见的变量,由用户自由定义变量名和变量的值。
环境变量:这种变量中主要保存的是和系统操作环境相关的数据,比如当前登录用户,用户的家目录,命令的提示符等。不是太好理解吧,那么大家还记得在 Windows 中,同一台电脑可以有多个用户登录,而且每个用户都可以定义自己的桌面样式和分辨率,这些其实就是Windows 的操作环境,可以当做是 Windows 的环境变量来理解。环境变量的变量名可以自由定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的。
位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
预定义变量:是 Bash 中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
[root@localhost ~]# 2name="test"
-bash: 2name=test: command not found
#变量名不能用数字开头
[root@localhost ~]# name = "test"
-bash: name: command not found
#等号左右两侧不能有空格
[root@localhost ~]# name=test bash
-bash: test bash: command not found
#变量的值如果有空格,必须用引号包含
[root@localhost ~]# name="hello bash"
#定义变量 name
[root@localhost ~]# echo $name
hello bash
#输出变量 name 的值
[root@localhost ~]# set [选项]
选项:
-u: 如果设定此选项,调用未声明变量时会报错(默认无任何提示)
-x: 如果设定此选项,在命令执行之前,会把命令先输出一次
+<参数>: 取消某个set曾启动的参数。
直接使用 set 命令,会查询系统中所有的变量,包含用户自定义变量和环境变量
当设置了-u 选项后,如果调用没有设定的变量会有报错。默认是没有任何输出的。
如果设定了-x 选项,会在每个命令执行之前,先把命令输出一次
[root@localhost ~]# unset 变量名
环境变量分为系统环境变量和用户环境变量。环境变量对所有shell环境起作用,而普通变量只对当前shell环境起作用。
[root@localhost ~]# export age="18"
#使用 export 声明的变量即是环境变量
env 命令和 set 命令的区别是,set 命令可以查看所有变量,而 env 命令只能查看环境变量。
[root@localhost ~]# env | grep age
[root@localhost ~]# unset age
env 命令可以查询到所有的环境变量,可是还有一些变量虽然不是环境变量,却是和 Bash 操作接口相关的变量,这些变量也对 Bash 操作终端起到了重要的作用。这些变量就只能用 set 命令来查看,下面只列出重要的内容:
[root@localhost ~]# set
BASH=/bin/bash
#Bash 的位置
BASH_VERSINFO=([0]="4" [1]="1" [2]="2" [3]="1" [4]="release"
[5]="i386-redhat-linux-gnu")
#Bash 版本
BASH_VERSION='4.1.2(1)-release'
#bash 的版本
COLORS=/etc/DIR_COLORS
#颜色记录文件
HISTFILE=/root/.bash_history
#历史命令保存文件
HISTFILESIZE=1000
#在文件当中记录的历史命令最大条数
HISTSIZE=1000
#在缓存中记录的历史命令最大条数
LANG=zh_CN.UTF-8
#语系环境
MACHTYPE=i386-redhat-linux-gnu
#软件类型是 i386 兼容类型
MAILCHECK=60
#每 60 秒去扫描新邮件
PPID=2166
#父 shell 的 PID。我们当前 Shell 是一个子 shell
PS1='[\u@\h \W]\$ '
#命令提示符
PS2='> '
#如果命令一行没有输入完成,第二行命令的提示符
UID=0
#当前用户的 UID
PATH 变量:系统查找命令的路径
先查询下 PATH 环境变量的值:
PATH 变量的值是用“:”
分割的路径,这些路径就是系统查找命令的路径。也就是说当我们输入了一个程序名,如果没有写入路径,系统就会到 PATH 变量定义的路径中去寻找,是否有可以执行的程序。如果找到则执行,否则会报“命令没有发现”的错误。
把脚本拷贝到 PATH 变量定义的路径中,也可以不输入路径而直接运行。
[root@localhost ~]# cp root/sh/hello.sh bin/
#拷贝 hello.sh 到/bin 目录
[root@localhost ~]# hello.sh
hello bash!
#hello.sh 可以直接执行了
可以修改 PATH 变量的值,而不是把程序脚本复制到/bin/目录中。通过变量的叠加实现:
[root@localhost ~]# PATH="$PATH":/root/sh
#在变量 PATH 的后面,加入/root/sh 目录
[root@localhost ~]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root/sh
#查询 PATH 的值,变量叠加生效了
当然这样定义的 PATH 变量只是临时生效,一旦重启或注销就会消失,如果想要永久生效,需要写入环境变量配置文件,后面讲解环境变量配置文件。
PS1 变量:命令提示符设置
PS1 是一个很有意思的变量,是用来定义命令行的提示符的,可以按照我们自己的需求来定义自己喜欢的提示符。PS1 可以支持以下这些选项:
\d:显示日期,格式为“星期 月 日”
\H:显示完整的主机名。如默认主机名“localhost.localdomain”
\h:显示简写主机名。如默认主机名“localhost”
\t:显示 24 小时制时间,格式为“HH:MM:SS”
\T:显示 12 小时制时间,格式为“HH:MM:SS”
\A:显示 24 小时制时间,格式为“HH:MM”
\@:显示 12 小时制时间,格式为“HH:MM am/pm”
\u:显示当前用户名
\v:显示 Bash 的版本信息
\w:显示当前所在目录的完整名称
\W:显示当前所在目录的最后一个目录
\#:执行的第几个命令
\$:提示符。如果是 root 用户会显示提示符为“#”,如果是普通用户会显示提示符为“$”
这些选项该怎么用啊?我们先看看 PS1 变量的默认值吧:
默认的提示符是显示“[用户名@简写主机名 最后所在目录]提示符”
在 PS1 变量中,如果是可以解释的符号,如“\u”
、“\h”
等,则显示这个符号的作用。如果是不能解释的符号,如“@”或“空格”,则原符号输出。那么我们修改下 PS1 变量,看看会出现什么情况吧:
[root@localhost ~]# PS1='[\u@\t \w]\$ '
#修改提示符为‘[用户名@当前时间 当前所在完整目录]提示符’
[root@04:46:40 ~]#cd usr/local/src/
#切换下当前所在目录,因为家目录是看不出来区别的
[root@04:47:29 /usr/local/src]#
#看到了吗?提示符按照我们的设计发生了变化
这里要小心,PS1 变量的值要用单引号包含,否则设置不生效。再举个例子吧:
[root@04:50:08 /usr/local/src]#PS1='[\u@\@ \h \# \W]\$'
[root@04:53 上午 localhost 31 src]#
#提示符又变了。\@:时间格式是 HH:MM am/pm;\#:会显示执行了多少个命令
LANG 变量定义了 Linux 系统的主语系环境,这个变量的默认值是:
这是因为我们 Linux 安装时,选择的是中文安装,所以默认的主语系变量是“zh_CN.UTF-8”。那么 Linux 中到底支持多少语系呢?可以使用以下命令查询:
支持这么多的语系,当前系统到底是什么语系呢?使用 locale 命令
直接查询:
我们还要通过文件/etc/sysconfig/i18n 定义系统的默认语系,查看下这个文件的内容:
这又是当前系统语系,又是默认语系,有没有快晕倒的感觉。解释下吧,可以这样理解,默认语系是下次重启之后系统所使用的语系,而当前系统语系是当前系统使用的语系。如果系统重启,会从默认语系配置文件/etc/sysconfig/i18n
中读出语系,然后赋予变量 LANG 让这个语系生效。也就是说,LANG 定义的语系只对当前系统生效,要想永久生效就要修改/etc/sysconfig/i18n 文件了。
位置参数变量 | 作用 |
---|---|
$n | n 为数字,$0 代表命令本身,$1-$9 代表第一到第九个参数,十以上的参数需要用大括号包含,如${10}. |
$* | 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体 |
$@ | 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待 |
$# | 这个变量代表命令行中所有参数的个数 |
[root@localhost sh]# vi count.sh
#!/bin/bash
num1=$1
#给 num1 变量赋值是第一个参数
num2=$2
#给 num2 变量赋值是第二个参数
sum=$(( $num1 + $num2))
#变量 sum 的和是 num1 加 num2
echo $sum
#打印变量 sum 的值
那么还有几个位置参数变量是干嘛的呢?我们在写个脚本来说明下
[root@localhost sh]# vi parameter.sh
#!/bin/bash
echo "A total of $# parameters"
#使用$#代表所有参数的个数
echo "The parameters is: $*"
#使用$*代表所有的参数
echo "The parameters is: $@"
#使用$@也代表所有参数
那么“$*”和“$@”有区别吗?还是有区别的,$*会把接收的所有参数当成一个整体对待,而$@则会区分对待接收到的所有参数。还是举个例子:
[root@localhost sh]# vi parameter2.sh
#!/bin/bash
for i in "$*"
#定义 for 循环,in 后面有几个值,for 会循环多少次,注意“$*”要用双引号括起来
#每次循环会把 in 后面的值赋予变量 i
#Shell 把$*中的所有参数看成是一个整体,所以这个 for 循环只会循环一次
do
echo "The parameters is: $i"
#打印变量$i 的值
done
x=1
#定义变量 x 的值为 1
for y in "$@"
#同样 in 后面的有几个值,for 循环几次,每次都把值赋予变量 y #可是 Shell 中把“$@”中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
echo "The parameter$x is: $y"
#输出变量 y 的值
x=$(( $x +1 ))
#然变量 x 每次循环都加 1,为了输出时看的更清楚
done
预定义变量 | 作用 |
---|---|
$? | 最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一个命令正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了 |
$$ | 当前进程的进程号(PID) |
$! | 后台运行的最后一个进程的进程号(PID) |
我们先来看看“$?”这个变量,看起来不好理解,我们还是举个例子:
[root@localhost sh]# ls
count.sh hello.sh parameter2.sh parameter.sh
#ls 命令正确执行
[root@localhost sh]# echo $?
0
#预定义变量“$?”的值是 0,证明上一个命令执行正确
[root@localhost sh]# ls install.log
ls: 无法访问 install.log: 没有那个文件或目录
#当前目录中没有 install.log 文件,所以 ls 命令报错了
[root@localhost sh]# echo $?
2
#变量“$?”返回一个非 0 的值,证明上一个命令没有正确执行
#至于错误的返回值到底是多少,是在编写 ls 命令时定义好的,如果碰到文件不存在就返回数值 2
接下来我们来说明下“$$”和“$!”这两个预定义变量,我们写个脚本吧:
[root@localhost sh]# vi variable.sh
#!/bin/bash
echo "The current process is $$"
#输出当前进程的 PID。;
#这个 PID 就是 variable.sh 这个脚本执行时,生成的进程的 PID
find /root -name hello.sh &
#使用 find 命令在 root 目录下查找 hello.sh 文件
#符号&的意思是把命令放入后台执行,工作管理在系统管理章节详细介绍
echo "The last one Daemon process is $!"
#输出这个后台执行命令的进程的 PID,也就是输出 find 命令的 PID 号
[root@localhost ~]# read [选项] [变量名]
选项:
-p “提示信息”: 在等待 read 输入时,输出提示信息
-t 秒数: read 命令会一直等待用户输入,使用此选项可以指定等待时间
-n 字符数: read 命令只接受指定的字符数,就会执行
-s: 隐藏输入的数据,适用于机密信息的输入
变量名:
变量名可以自定义,如果不指定变量名,会把输入保存入默认变量 REPLY
如果只提供了一个变量名,则整个输入行赋予该变量
如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上的最后一个变量取得剩余的所有字
写个例子来解释下 read 命令:
[root@localhost sh]# vi read.sh
#!/bin/bash
read -t 30 -p "Please input your name: " name
#提示“请输入姓名”并等待 30 秒,把用户的输入保存入变量 name 中
echo "Name is $name"
#看看变量“$name”中是否保存了你的输入
read -s -t 30 -p "Please enter your age: " age
#提示“请输入年龄”并等待 30 秒,把用户的输入保存入变量 age 中 #年龄是隐私,所以我们用“-s”选项隐藏输入
echo -e "\n"
#调整输出格式,如果不输出换行,一会的年龄输出不会换行
echo "Age is $age"
read -n 1 -t 30 -p "Please select your gender[M/F]: " gender
#提示“请选择性别”并等待 30 秒,把用户的输入保存入变量 gender
#使用“-n 1”选项只接收一个输入字符就会执行(都不用输入回车)
echo -e "\n"
echo "Sex is $gender"